﻿using System;
using System.Collections.Generic;
using System.Linq;
using GigaSite.Domain.Entities;
using GigaSite.Domain.Interfaces.Repositories;

namespace GigaSite.Domain.DAL.Repositories
{
    /// <summary>
    /// СУБД реализация репозитория сайтов
    /// </summary>
    public class SitesRepository: BaseRepository<Site>, ISitesRepository
    {
        /// <summary>
        /// Репозиторий изображений
        /// </summary>
        public IImagesRepository ImagesRepository { get; set; }

        /// <summary>
        /// Конструктор
        /// </summary>
        /// <param name="dataContext">Контекст данных</param>
        /// <param name="imagesRepository">Репозиторий изображений</param>
        public SitesRepository(GigaDataContext dataContext, IImagesRepository imagesRepository) : base(dataContext)
        {
            ImagesRepository = imagesRepository;
        }

        /// <summary>
        /// Загружает указанную сущность по ее идентификатору
        /// </summary>
        /// <param name="id">Идентификатор сущности</param>
        /// <returns>Сущность с указанным идентификатором или Null</returns>
        public override Site Load(long id)
        {
            return Find(s => s.Id == id);
        }

        /// <summary>
        /// Добавляет указанный сайт в блокнот сайтов пользователя
        /// </summary>
        /// <param name="user">Пользователь</param>
        /// <param name="site">Сайт</param>
        public void AddSiteToUser(User user, Site site)
        {
            // Ищем маппинг для пользователя
            var mapping = DataContext.SiteToUserMappings.FirstOrDefault(m => m.User == user && m.Site == site);
            if (mapping == null)
            {
                // Добавляем маппинг если его нет
                mapping = new SiteToUserMapping()
                              {
                                  DateCreated = DateTime.Now,
                                  User = user,
                                  Site = site,
                                  Position = user.SiteToUserMappings.Select(m => m.Position).Max()+1
                              };
                DataContext.SiteToUserMappings.InsertOnSubmit(mapping);
            }
        }

        /// <summary>
        /// Удаляет сайт из блокнота сайтов пользователя
        /// </summary>
        /// <param name="user">Пользователь</param>
        /// <param name="site"></param>
        public void RemoveSiteFromUser(User user, Site site)
        {
            // Ищем маппинг для пользователя
            var mapping = DataContext.SiteToUserMappings.FirstOrDefault(m => m.User == user && m.Site == site);
            if (mapping != null)
            {
                // Удаляем
                DataContext.SiteToUserMappings.DeleteOnSubmit(mapping);
            }
        }

        /// <summary>
        /// Добавляет сайт в указанную категорию
        /// </summary>
        /// <param name="category">Категория</param>
        /// <param name="site">Сайт</param>
        public void AddSiteToCategory(Category category, Site site)
        {
            // Ищем маппинг для категории
            var mapping = DataContext.SiteToCategoryMappings.FirstOrDefault(m => m.Category == category && m.Site == site);
            if (mapping == null)
            {
                mapping = new SiteToCategoryMapping()
                              {
                                  DateCreated = DateTime.Now,
                                  Category = category,
                                  Site = site
                              };
                DataContext.SiteToCategoryMappings.InsertOnSubmit(mapping);
            }
        }

        /// <summary>
        /// Удаляет сайт из указанной категории
        /// </summary>
        /// <param name="category">Категория</param>
        /// <param name="site">сайт</param>
        public void RemoveSiteFromCategory(Category category, Site site)
        {
            // Ищем маппинг для категории
            var mapping = DataContext.SiteToCategoryMappings.FirstOrDefault(m => m.Category == category && m.Site == site);
            if (mapping != null)
            {
                // Удаляем
                DataContext.SiteToCategoryMappings.DeleteOnSubmit(mapping);
            }
        }

        /// <summary>
        /// Устанавливает категории, в которых должен находиться переданный сайт
        /// </summary>
        /// <param name="site">Сайт</param>
        /// <param name="categories">список категорий</param>
        public void SetSiteCategories(Site site, IEnumerable<Category> categories)
        {
            // Ищем категории связь с которыми нужно удалить
            var categoriesToDelete = site.SiteToCategoryMappings.Where(m => !categories.Any(category => category.Id == m.CategoryId));

            // Ищем категории связь с которыми нужно добавить
            var categoriesToAdd = categories.Where(category => !site.SiteToCategoryMappings.Any(mapping => mapping.CategoryId == category.Id));

            // Выполняем действия
            DataContext.SiteToCategoryMappings.DeleteAllOnSubmit(categoriesToDelete);
            DataContext.SiteToCategoryMappings.InsertAllOnSubmit(
                categoriesToAdd.Select(category => new SiteToCategoryMapping()
                                                       {
                                                           Site = site,
                                                           Category = category,
                                                           DateCreated = DateTime.Now
                                                       }));
        }

        /// <summary>
        /// Удаляет сущность из репозитория
        /// </summary>
        /// <param name="entity">Сущность для удаления</param>
        public override void Delete(Site entity)
        {
            // Удаляем все связи сайта с категориями
            DataContext.SiteToCategoryMappings.DeleteAllOnSubmit(entity.SiteToCategoryMappings);
            base.Delete(entity);
        }
    }
}